import { rxccconfig } from './RxCCConfig';
import { Observable, EMPTY, Subscription, filter } from 'rxjs';
import { Button, isValid, warn, Node, KeyCode } from "cc";
import { KeyUp } from './KeyEvent';


export function BindButtonEx(button: Button, hotKeyCode?: KeyCode): Observable<Button> {
    if (!button) { warn('BindButton, button is null'); return EMPTY; }
    return new Observable(observer => {
        const clickCallback = param => {
            rxccconfig.buttonWillClickCommand.execute({ node: button.node });
            observer.next(param);
        }
        button.node.on(Button.EventType.CLICK, clickCallback);

        const touchStartCallback = _ => {
            rxccconfig.buttonTouchStartCommand.execute({ node: button.node });
        };
        const touchEndCallback = _ => {
            rxccconfig.buttonTouchEndCommand.execute({ node: button.node });
        };
        button.node.on(Node.EventType.TOUCH_START, touchStartCallback)
        button.node.on(Node.EventType.TOUCH_END, touchEndCallback)

        return () => {
            if (isValid(button.node)) {
                button.node.off(Button.EventType.CLICK, clickCallback);
                button.node.off(Node.EventType.TOUCH_START, touchStartCallback);
                button.node.off(Node.EventType.TOUCH_END, touchEndCallback);
            }
        }
    })
}

export function BindButton(button: Button, hotKeyCode?: KeyCode): Observable<Button> {
    if (!button) { warn('BindButton, button is null'); return EMPTY; }
    return new Observable(observer => {
        const clickCallback = param => {
            rxccconfig.buttonWillClickCommand.execute({ node: button.node });
            observer.next(param);
        }
        button.node.on(Button.EventType.CLICK, clickCallback);
        return () => {
            if (isValid(button.node)) {
                button.node.off(Button.EventType.CLICK, clickCallback);
            }
        }
    })
}

declare module "cc" {
    interface Button {
        subscribe: (param: (button: Button) => void) => Subscription;
        asObservable: () => Observable<Button>;
    }
}

Button.prototype.asObservable = function (): Observable<Button> {
    if (!isValid(this?.node)) return EMPTY;
    return BindButton(this);
}

Button.prototype.subscribe = function (param: (button: Button) => void): Subscription {
    let self: Button = this;
    return self.asObservable().subscribe(param);
}